package com.jsy.common.util.codeGenerate;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 建表语句代码生成工具
 * 支持生成实体类、Mapper接口、XML映射、Service层、Controller层及校验注解
 * AI生成 待调试和完善
 */
public class CodeGenerationTool {
    
    // 包路径配置
    private static final String ENTITY_PACKAGE = "com.example.entity";
    private static final String MAPPER_PACKAGE = "com.example.mapper";
    private static final String SERVICE_PACKAGE = "com.example.service";
    private static final String SERVICE_IMPL_PACKAGE = "com.example.service.impl";
    private static final String CONTROLLER_PACKAGE = "com.example.controller";
    
    // 数据类型映射
    private static final Map<String, String> DB_TYPE_MAPPING = new HashMap<>();
    static {
        DB_TYPE_MAPPING.put("int", "Integer");
        DB_TYPE_MAPPING.put("integer", "Integer");
        DB_TYPE_MAPPING.put("bigint", "Long");
        DB_TYPE_MAPPING.put("varchar", "String");
        DB_TYPE_MAPPING.put("char", "String");
        DB_TYPE_MAPPING.put("text", "String");
        DB_TYPE_MAPPING.put("datetime", "Date");
        DB_TYPE_MAPPING.put("timestamp", "Date");
        DB_TYPE_MAPPING.put("decimal", "BigDecimal");
        DB_TYPE_MAPPING.put("double", "Double");
        DB_TYPE_MAPPING.put("float", "Float");
        DB_TYPE_MAPPING.put("tinyint", "Boolean");
    }
    
    // 校验注解映射
    private static final Map<String, String> CONSTRAINT_MAPPING = new HashMap<>();
    static {
        CONSTRAINT_MAPPING.put("NOT NULL", "@NotNull");
        CONSTRAINT_MAPPING.put("UNIQUE", "@Unique"); // 自定义注解，需额外实现
        CONSTRAINT_MAPPING.put("CHECK", "@Pattern"); // 简化处理，实际需根据CHECK条件定制
    }
    
    /**
     * 主入口：从DDL生成完整代码
     */
    public static void generateFromDDL(String ddl, String outputPath) throws IOException {
        TableInfo tableInfo = parseTableDDL(ddl);
        
        // 生成实体类
        generateEntityClass(tableInfo, outputPath);
        
        // 生成Mapper接口
        generateMapperInterface(tableInfo, outputPath);
        
        // 生成Mapper XML
        generateMapperXML(tableInfo, outputPath);
        
        // 生成Service接口
        generateServiceInterface(tableInfo, outputPath);
        
        // 生成Service实现
        generateServiceImpl(tableInfo, outputPath);
        
        // 生成Controller
        generateController(tableInfo, outputPath);
        
        System.out.println("代码生成完成，路径：" + outputPath);
    }
    
    /**
     * 解析建表语句
     */
    private static TableInfo parseTableDDL(String ddl) {
        TableInfo tableInfo = new TableInfo();
        
        // 提取表名
        Pattern tablePattern = Pattern.compile("CREATE TABLE\\s+`?([a-zA-Z0-9_]+)`?\\s*\\(");
        Matcher tableMatcher = tablePattern.matcher(ddl);
        if (tableMatcher.find()) {
            tableInfo.setTableName(tableMatcher.group(1));
            tableInfo.setClassName(underlineToCamel(tableInfo.getTableName(), true));
        }
        
        // 提取字段信息
        Pattern columnPattern = Pattern.compile("`?([a-zA-Z0-9_]+)`?\\s+([a-zA-Z0-9()]+)\\s*(.*?)(?:,|\\))");
        Matcher columnMatcher = columnPattern.matcher(ddl);
        
        List<FieldInfo> fieldList = new ArrayList<>();
        String primaryKey = null;
        
        while (columnMatcher.find()) {
            String columnName = columnMatcher.group(1);
            String columnType = columnMatcher.group(2).toLowerCase();
            String constraints = columnMatcher.group(3).toLowerCase();
            
            FieldInfo field = new FieldInfo();
            field.setColumnName(columnName);
            field.setJavaName(underlineToCamel(columnName, false));
            field.setJavaType(mapDbTypeToJavaType(columnType));
            field.setConstraints(constraints);
            
            // 检查是否为主键
            if (constraints.contains("primary key")) {
                primaryKey = columnName;
                field.setPrimaryKey(true);
            }
            
            // 提取校验注解
            List<String> validationAnnotations = extractValidationAnnotations(constraints);
            field.setValidationAnnotations(validationAnnotations);
            
            fieldList.add(field);
        }
        
        tableInfo.setFieldList(fieldList);
        tableInfo.setPrimaryKey(primaryKey);
        
        return tableInfo;
    }
    
    /**
     * 数据库类型映射到Java类型
     */
    private static String mapDbTypeToJavaType(String dbType) {
        // 处理带长度的类型如varchar(255)
        String baseType = dbType.split("\\(")[0];
        
        // 处理常见的时间类型
        if (baseType.contains("date") || baseType.contains("time")) {
            return "Date";
        }
        
        return DB_TYPE_MAPPING.getOrDefault(baseType, "String");
    }
    
    /**
     * 提取校验注解
     */
    private static List<String> extractValidationAnnotations(String constraints) {
        List<String> annotations = new ArrayList<>();
        
        if (constraints.contains("not null")) {
            annotations.add("@NotNull");
        }
        
        if (constraints.contains("unique")) {
            annotations.add("@Unique"); // 需自定义实现
        }
        
        // 提取长度约束
        Pattern lengthPattern = Pattern.compile("\\((\\d+)\\)");
        Matcher lengthMatcher = lengthPattern.matcher(constraints);
        if (lengthMatcher.find()) {
            int length = Integer.parseInt(lengthMatcher.group(1));
            annotations.add("@Size(max = " + length + ")");
        }
        
        return annotations;
    }
    
    /**
     * 下划线转驼峰
     */
    private static String underlineToCamel(String input, boolean firstUpper) {
        StringBuilder result = new StringBuilder();
        String[] parts = input.split("_");
        
        for (int i = 0; i < parts.length; i++) {
            String part = parts[i];
            if (i == 0 && !firstUpper) {
                result.append(part.toLowerCase());
            } else {
                result.append(part.substring(0, 1).toUpperCase())
                      .append(part.substring(1).toLowerCase());
            }
        }
        
        return result.toString();
    }
    
    /**
     * 生成实体类
     */
    private static void generateEntityClass(TableInfo tableInfo, String outputPath) throws IOException {
        StringBuilder code = new StringBuilder();
        
        code.append("package ").append(ENTITY_PACKAGE).append(";\n\n");
        code.append("import com.baomidou.mybatisplus.annotation.TableName;\n");
        code.append("import lombok.Data;\n");
        
        // 添加校验注解的导入
        code.append("import javax.validation.constraints.*;\n");
        code.append("import java.io.Serializable;\n");
        
        // 检查是否需要导入Date或BigDecimal
        boolean needDate = false;
        boolean needBigDecimal = false;
        
        for (FieldInfo field : tableInfo.getFieldList()) {
            if ("Date".equals(field.getJavaType())) {
                needDate = true;
            }
            if ("BigDecimal".equals(field.getJavaType())) {
                needBigDecimal = true;
            }
        }
        
        if (needDate) {
            code.append("import java.util.Date;\n");
        }
        
        if (needBigDecimal) {
            code.append("import java.math.BigDecimal;\n");
        }
        
        code.append("\n");
        code.append("/**\n");
        code.append(" * ").append(tableInfo.getClassName()).append("实体类\n");
        code.append(" */\n");
        code.append("@Data\n");
        code.append("@TableName(\"").append(tableInfo.getTableName()).append("\")\n");
        code.append("public class ").append(tableInfo.getClassName()).append(" implements Serializable {\n\n");
        
        // 生成字段
        for (FieldInfo field : tableInfo.getFieldList()) {
            // 添加校验注解
            for (String annotation : field.getValidationAnnotations()) {
                code.append("    ").append(annotation).append("\n");
            }
            
            code.append("    private ").append(field.getJavaType()).append(" ").append(field.getJavaName()).append(";\n\n");
        }
        
        code.append("}");
        
        writeToFile(code.toString(), outputPath, ENTITY_PACKAGE, tableInfo.getClassName() + ".java");
    }
    
    /**
     * 生成Mapper接口
     */
    private static void generateMapperInterface(TableInfo tableInfo, String outputPath) throws IOException {
        StringBuilder code = new StringBuilder();
        
        code.append("package ").append(MAPPER_PACKAGE).append(";\n\n");
        code.append("import com.baomidou.mybatisplus.core.mapper.BaseMapper;\n");
        code.append("import ").append(ENTITY_PACKAGE).append(".").append(tableInfo.getClassName()).append(";\n");
        code.append("import org.apache.ibatis.annotations.Mapper;\n\n");
        
        code.append("/**\n");
        code.append(" * ").append(tableInfo.getClassName()).append("数据库访问接口\n");
        code.append(" */\n");
        code.append("@Mapper\n");
        code.append("public interface ").append(tableInfo.getClassName()).append("Mapper extends BaseMapper<").append(tableInfo.getClassName()).append("> {\n\n");
        
        // 添加自定义查询方法示例
        code.append("    /**\n");
        code.append("     * 根据名称查询\n");
        code.append("     */\n");
        code.append("    ").append(tableInfo.getClassName()).append(" selectByName(String name);\n\n");
        
        code.append("}");
        
        writeToFile(code.toString(), outputPath, MAPPER_PACKAGE, tableInfo.getClassName() + "Mapper.java");
    }
    
    /**
     * 生成Mapper XML
     */
    private static void generateMapperXML(TableInfo tableInfo, String outputPath) throws IOException {
        StringBuilder xml = new StringBuilder();
        
        xml.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
        xml.append("<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n");
        xml.append("<mapper namespace=\"").append(MAPPER_PACKAGE).append(".").append(tableInfo.getClassName()).append("Mapper\">\n\n");
        
        // 生成resultMap
        xml.append("    <resultMap id=\"BaseResultMap\" type=\"").append(ENTITY_PACKAGE).append(".").append(tableInfo.getClassName()).append("\">\n");
        
        for (FieldInfo field : tableInfo.getFieldList()) {
            xml.append("        <result column=\"").append(field.getColumnName()).append("\" property=\"").append(field.getJavaName()).append("\" jdbcType=\"").append(mapJavaTypeToJdbcType(field.getJavaType())).append("\"/>\n");
        }
        
        xml.append("    </resultMap>\n\n");
        
        // 生成自定义查询语句
        xml.append("    <select id=\"selectByName\" resultMap=\"BaseResultMap\">\n");
        xml.append("        SELECT * FROM ").append(tableInfo.getTableName()).append(" WHERE name = #{name}\n");
        xml.append("    </select>\n\n");
        
        xml.append("</mapper>");
        
        writeToFile(xml.toString(), outputPath, MAPPER_PACKAGE.replace(".", "/"), tableInfo.getClassName() + "Mapper.xml");
    }
    
    /**
     * Java类型映射到JDBC类型
     */
    private static String mapJavaTypeToJdbcType(String javaType) {
        switch (javaType) {
            case "Integer":
                return "INTEGER";
            case "Long":
                return "BIGINT";
            case "String":
                return "VARCHAR";
            case "Date":
                return "TIMESTAMP";
            case "BigDecimal":
                return "DECIMAL";
            case "Double":
                return "DOUBLE";
            case "Float":
                return "FLOAT";
            case "Boolean":
                return "TINYINT";
            default:
                return "VARCHAR";
        }
    }
    
    /**
     * 生成Service接口
     */
    private static void generateServiceInterface(TableInfo tableInfo, String outputPath) throws IOException {
        StringBuilder code = new StringBuilder();
        
        code.append("package ").append(SERVICE_PACKAGE).append(";\n\n");
        code.append("import com.baomidou.mybatisplus.extension.service.IService;\n");
        code.append("import ").append(ENTITY_PACKAGE).append(".").append(tableInfo.getClassName()).append(";\n");
        code.append("import java.util.List;\n\n");
        
        code.append("/**\n");
        code.append(" * ").append(tableInfo.getClassName()).append("业务接口\n");
        code.append(" */\n");
        code.append("public interface ").append(tableInfo.getClassName()).append("Service extends IService<").append(tableInfo.getClassName()).append("> {\n\n");
        
        // 添加自定义业务方法
        code.append("    /**\n");
        code.append("     * 根据条件查询列表\n");
        code.append("     */\n");
        code.append("    List<").append(tableInfo.getClassName()).append("> listByCondition(").append(tableInfo.getClassName()).append(" condition);\n\n");
        
        code.append("}");
        
        writeToFile(code.toString(), outputPath, SERVICE_PACKAGE, tableInfo.getClassName() + "Service.java");
    }
    
    /**
     * 生成Service实现
     */
    private static void generateServiceImpl(TableInfo tableInfo, String outputPath) throws IOException {
        StringBuilder code = new StringBuilder();
        
        code.append("package ").append(SERVICE_IMPL_PACKAGE).append(";\n\n");
        code.append("import ").append(SERVICE_PACKAGE).append(".").append(tableInfo.getClassName()).append("Service;\n");
        code.append("import ").append(ENTITY_PACKAGE).append(".").append(tableInfo.getClassName()).append(";\n");
        code.append("import ").append(MAPPER_PACKAGE).append(".").append(tableInfo.getClassName()).append("Mapper;\n");
        code.append("import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\n");
        code.append("import org.springframework.stereotype.Service;\n");
        code.append("import java.util.List;\n\n");
        
        code.append("/**\n");
        code.append(" * ").append(tableInfo.getClassName()).append("业务实现\n");
        code.append(" */\n");
        code.append("@Service\n");
        code.append("public class ").append(tableInfo.getClassName()).append("ServiceImpl extends ServiceImpl<").append(tableInfo.getClassName()).append("Mapper, ").append(tableInfo.getClassName()).append("> implements ").append(tableInfo.getClassName()).append("Service {\n\n");
        
        // 实现自定义业务方法
        code.append("    @Override\n");
        code.append("    public List<").append(tableInfo.getClassName()).append("> listByCondition(").append(tableInfo.getClassName()).append(" condition) {\n");
        code.append("        // 示例：根据条件查询\n");
        code.append("        return baseMapper.selectList(null);\n");
        code.append("    }\n\n");
        
        code.append("}");
        
        writeToFile(code.toString(), outputPath, SERVICE_IMPL_PACKAGE, tableInfo.getClassName() + "ServiceImpl.java");
    }
    
    /**
     * 生成Controller
     */
    private static void generateController(TableInfo tableInfo, String outputPath) throws IOException {
        StringBuilder code = new StringBuilder();
        
        code.append("package ").append(CONTROLLER_PACKAGE).append(";\n\n");
        code.append("import ").append(SERVICE_PACKAGE).append(".").append(tableInfo.getClassName()).append("Service;\n");
        code.append("import ").append(ENTITY_PACKAGE).append(".").append(tableInfo.getClassName()).append(";\n");
        code.append("import org.springframework.beans.factory.annotation.Autowired;\n");
        code.append("import org.springframework.web.bind.annotation.*;\n");
        code.append("import javax.validation.Valid;\n");
        code.append("import java.util.List;\n\n");
        
        code.append("/**\n");
        code.append(" * ").append(tableInfo.getClassName()).append("控制器\n");
        code.append(" */\n");
        code.append("@RestController\n");
        code.append("@RequestMapping(\"/").append(underlineToCamel(tableInfo.getTableName(), false)).append("\")\n");
        code.append("public class ").append(tableInfo.getClassName()).append("Controller {\n\n");
        
        code.append("    @Autowired\n");
        code.append("    private ").append(tableInfo.getClassName()).append("Service ").append(underlineToCamel(tableInfo.getClassName(), false)).append("Service;\n\n");
        
        // 添加方法
        // 1. 查询单个
        code.append("    /**\n");
        code.append("     * 根据ID查询\n");
        code.append("     */\n");
        code.append("    @GetMapping(\"/{id}\")\n");
        code.append("    public ").append(tableInfo.getClassName()).append(" getById(@PathVariable Long id) {\n");
        code.append("        return ").append(underlineToCamel(tableInfo.getClassName(), false)).append("Service.getById(id);\n");
        code.append("    }\n\n");
        
        // 2. 查询列表
        code.append("    /**\n");
        code.append("     * 查询列表\n");
        code.append("     */\n");
        code.append("    @GetMapping\n");
        code.append("    public List<").append(tableInfo.getClassName()).append("> list() {\n");
        code.append("        return ").append(underlineToCamel(tableInfo.getClassName(), false)).append("Service.list();\n");
        code.append("    }\n\n");
        
        // 3. 添加
        code.append("    /**\n");
        code.append("     * 添加\n");
        code.append("     */\n");
        code.append("    @PostMapping\n");
        code.append("    public boolean save(@Valid @RequestBody ").append(tableInfo.getClassName()).append(" ").append(underlineToCamel(tableInfo.getClassName(), false)).append(") {\n");
        code.append("        return ").append(underlineToCamel(tableInfo.getClassName(), false)).append("Service.save(").append(underlineToCamel(tableInfo.getClassName(), false)).append(");\n");
        code.append("    }\n\n");
        
        // 4. 更新
        code.append("    /**\n");
        code.append("     * 更新\n");
        code.append("     */\n");
        code.append("    @PutMapping\n");
        code.append("    public boolean update(@Valid @RequestBody ").append(tableInfo.getClassName()).append(" ").append(underlineToCamel(tableInfo.getClassName(), false)).append(") {\n");
        code.append("        return ").append(underlineToCamel(tableInfo.getClassName(), false)).append("Service.updateById(").append(underlineToCamel(tableInfo.getClassName(), false)).append(");\n");
        code.append("    }\n\n");
        
        // 5. 删除
        code.append("    /**\n");
        code.append("     * 删除\n");
        code.append("     */\n");
        code.append("    @DeleteMapping(\"/{id}\")\n");
        code.append("    public boolean delete(@PathVariable Long id) {\n");
        code.append("        return ").append(underlineToCamel(tableInfo.getClassName(), false)).append("Service.removeById(id);\n");
        code.append("    }\n\n");
        
        code.append("}");
        
        writeToFile(code.toString(), outputPath, CONTROLLER_PACKAGE, tableInfo.getClassName() + "Controller.java");
    }
    
    /**
     * 写入文件
     */
    private static void writeToFile(String content, String basePath, String packageName, String fileName) throws IOException {
        String packagePath = packageName.replace(".", File.separator);
        String filePath = basePath + File.separator + packagePath;
        
        File dir = new File(filePath);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        
        File file = new File(filePath, fileName);
        try (FileWriter writer = new FileWriter(file)) {
            writer.write(content);
        }
    }
    
    /**
     * 表信息类
     */
    static class TableInfo {
        private String tableName;
        private String className;
        private String primaryKey;
        private List<FieldInfo> fieldList;
        
        // Getters and Setters
        public String getTableName() {
            return tableName;
        }
        
        public void setTableName(String tableName) {
            this.tableName = tableName;
        }
        
        public String getClassName() {
            return className;
        }
        
        public void setClassName(String className) {
            this.className = className;
        }
        
        public String getPrimaryKey() {
            return primaryKey;
        }
        
        public void setPrimaryKey(String primaryKey) {
            this.primaryKey = primaryKey;
        }
        
        public List<FieldInfo> getFieldList() {
            return fieldList;
        }
        
        public void setFieldList(List<FieldInfo> fieldList) {
            this.fieldList = fieldList;
        }
    }
    
    /**
     * 字段信息类
     */
    static class FieldInfo {
        private String columnName;
        private String javaName;
        private String javaType;
        private String constraints;
        private boolean primaryKey;
        private List<String> validationAnnotations;
        
        // Getters and Setters
        public String getColumnName() {
            return columnName;
        }
        
        public void setColumnName(String columnName) {
            this.columnName = columnName;
        }
        
        public String getJavaName() {
            return javaName;
        }
        
        public void setJavaName(String javaName) {
            this.javaName = javaName;
        }
        
        public String getJavaType() {
            return javaType;
        }
        
        public void setJavaType(String javaType) {
            this.javaType = javaType;
        }
        
        public String getConstraints() {
            return constraints;
        }
        
        public void setConstraints(String constraints) {
            this.constraints = constraints;
        }
        
        public boolean isPrimaryKey() {
            return primaryKey;
        }
        
        public void setPrimaryKey(boolean primaryKey) {
            this.primaryKey = primaryKey;
        }
        
        public List<String> getValidationAnnotations() {
            return validationAnnotations;
        }
        
        public void setValidationAnnotations(List<String> validationAnnotations) {
            this.validationAnnotations = validationAnnotations;
        }
    }
    
    /**
     * 示例：使用方法
     */
    public static void main(String[] args) {
        String ddl = "CREATE TABLE `user` (\n" +
                     "  `id` bigint(20) NOT NULL AUTO_INCREMENT,\n" +
                     "  `username` varchar(50) NOT NULL,\n" +
                     "  `password` varchar(100) NOT NULL,\n" +
                     "  `email` varchar(50) DEFAULT NULL,\n" +
                     "  `age` int(11) DEFAULT NULL,\n" +
                     "  `create_time` datetime DEFAULT CURRENT_TIMESTAMP,\n" +
                     "  PRIMARY KEY (`id`),\n" +
                     "  UNIQUE KEY `idx_username` (`username`)\n" +
                     ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;";
        
        try {
            generateFromDDL(ddl, "D:/generated-code");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}